home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 45
/
Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso
/
Aminet
/
gfx
/
x11
/
x3270_3_2_16.lha
/
amiga_src
/
printer.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-06-23
|
11KB
|
473 lines
/*
* Copyright 2000 by Paul Mattes.
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*/
/*
* printer.c
* Printer session support
*/
#include "globals.h"
#if (defined(C3270) || defined(X3270_DISPLAY)) && defined(X3270_PRINTER) /*[*/
#if defined(X3270_DISPLAY) /*[*/
#include <X11/StringDefs.h>
#include <X11/Xaw/Dialog.h>
#endif /*]*/
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <stdarg.h>
#include <fcntl.h>
#include "3270ds.h"
#include "appres.h"
#include "objects.h"
#include "resources.h"
#include "ctlr.h"
#include "ctlrc.h"
#include "hostc.h"
#include "menubarc.h"
#include "popupsc.h"
#include "printerc.h"
#include "printc.h"
#include "savec.h"
#if defined(C3270) /*[*/
#include "screenc.h"
#endif /*]*/
#include "tablesc.h"
#include "telnetc.h"
#include "trace_dsc.h"
#include "utilc.h"
#define PRINTER_BUF 1024
/* Statics */
static int printer_pid = -1;
#if defined(X3270_DISPLAY) /*[*/
static Widget lu_shell = (Widget)NULL;
#endif /*]*/
static struct pr3o {
int fd; /* file descriptor */
unsigned long input_id; /* input ID */
unsigned long timeout_id; /* timeout ID */
int count; /* input count */
char buf[PRINTER_BUF]; /* input buffer */
} printer_stdout = { -1, 0L, 0L, 0 },
printer_stderr = { -1, 0L, 0L, 0 };
static void printer_output(void);
static void printer_error(void);
static void printer_otimeout(void);
static void printer_etimeout(void);
static void printer_dump(struct pr3o *p, Boolean is_err, Boolean is_dead);
static void printer_host_connect(Boolean connected unused);
/* Globals */
/*
* Printer Start-up function
* If 'lu' is non-NULL, then use the specific-LU form.
* If not, use the assoc form.
*/
void
printer_start(const char *lu)
{
const char *cmdlineName;
const char *cmdline;
const char *cmd;
int cmd_len = 0;
const char *s;
char *cmd_text;
char c;
int stdout_pipe[2];
int stderr_pipe[2];
static Boolean registered = False;
#if defined(X3270_DISPLAY) /*[*/
/* Make sure the popups are initted. */
printer_popup_init();
#endif /*]*/
/* Register interest in host connects and mode changes. */
if (!registered) {
register_schange(ST_CONNECT, printer_host_connect);
register_schange(ST_3270_MODE, printer_host_connect);
registered = True;
}
/* Can't start two. */
if (printer_pid != -1) {
popup_an_error("printer is already running");
return;
}
/* Gotta be in 3270 mode. */
if (!IN_3270) {
popup_an_error("Not in 3270 mode");
return;
}
/* Select the command line to use. */
if (lu == CN) {
/* Associate with the current session. */
/* Gotta be in TN3270E mode. */
if (!IN_TN3270E) {
popup_an_error("Not in TN3270E mode");
return;
}
/* Gotta be connected to an LU. */
if (connected_lu == CN) {
popup_an_error("Not connected to a specific LU");
return;
}
lu = connected_lu;
cmdlineName = ResAssocCommand;
} else {
/* Specific LU passed in. */
cmdlineName = ResLuCommandLine;
}
/* Fetch the command line and command resources. */
cmdline = get_resource(cmdlineName);
if (cmdline == CN) {
popup_an_error("%s resource not defined", cmdlineName);
return;
}
cmd = get_resource(ResPrinterCommand);
if (cmd == CN) {
popup_an_error("printer.command resource not defined");
return;
}
/* Construct the command line. */
/* Figure out how long it will be. */
cmd_len = strlen(cmdline) + 1;
s = cmdline;
while ((s = strstr(s, "%L%")) != CN) {
cmd_len += strlen(lu) - 3;
s += 3;
}
s = cmdline;
while ((s = strstr(s, "%H%")) != CN) {
cmd_len += strlen(hostname) - 3;
s += 3;
}
s = cmdline;
while ((s = strstr(s, "%C%")) != CN) {
cmd_len += strlen(cmd) - 3;
s += 3;
}
/* Allocate a string buffer and substitute into it. */
cmd_text = Malloc(cmd_len);
cmd_text[0] = '\0';
for (s = cmdline; (c = *s) != '\0'; s++) {
char buf1[2];
if (c == '%') {
if (!strncmp(s+1, "L%", 2)) {
(void) strcat(cmd_text, lu);
s += 2;
continue;
} else if (!strncmp(s+1, "H%", 2)) {
(void) strcat(cmd_text, hostname);
s += 2;
continue;
} else if (!strncmp(s+1, "C%", 2)) {
(void) strcat(cmd_text, cmd);
s += 2;
continue;
}
}
buf1[0] = c;
buf1[1] = '\0';
(void) strcat(cmd_text, buf1);
}
trace_event("Printer command line: %s\n", cmd_text);
#ifndef AMIGA
/* Make pipes for printer's stdout and stderr. */
if (pipe(stdout_pipe) < 0) {
popup_an_errno(errno, "pipe() failed");
Free(cmd_text);
return;
}
(void) fcntl(stdout_pipe[0], F_SETFD, 1);
if (pipe(stderr_pipe) < 0) {
popup_an_errno(errno, "pipe() failed");
(void) close(stdout_pipe[0]);
(void) close(stdout_pipe[1]);
Free(cmd_text);
return;
}
(void) fcntl(stderr_pipe[0], F_SETFD, 1);
/* Fork and exec the printer session. */
switch (printer_pid = fork()) {
case 0: /* child process */
(void) dup2(stdout_pipe[1], 1);
(void) close(stdout_pipe[1]);
(void) dup2(stderr_pipe[1], 2);
(void) close(stderr_pipe[1]);
if (setsid() < 0) {
perror("setsid");
_exit(1);
}
(void) execlp("/bin/sh", "sh", "-c", cmd_text, CN);
(void) perror("exec(printer)");
_exit(1);
default: /* parent process */
(void) close(stdout_pipe[1]);
printer_stdout.fd = stdout_pipe[0];
(void) close(stderr_pipe[1]);
printer_stderr.fd = stderr_pipe[0];
printer_stdout.input_id = AddInput(printer_stdout.fd,
printer_output);
printer_stderr.input_id = AddInput(printer_stderr.fd,
printer_error);
++children;
break;
case -1: /* error */
popup_an_errno(errno, "fork()");
(void) close(stdout_pipe[0]);
(void) close(stdout_pipe[1]);
(void) close(stderr_pipe[0]);
(void) close(stderr_pipe[1]);
break;
}
#endif
Free(cmd_text);
/* Tell everyone else. */
st_changed(ST_PRINTER, True);
}
/* There's data from the printer session. */
static void
printer_data(struct pr3o *p, Boolean is_err)
{
int space;
int nr;
static char exitmsg[] = "Printer session exited";
/* Read whatever there is. */
space = PRINTER_BUF - p->count - 1;
nr = read(p->fd, p->buf + p->count, space);
/* Handle read errors and end-of-file. */
if (nr < 0) {
popup_an_errno(errno, "printer session pipe input");
printer_stop();
return;
}
if (nr == 0) {
if (printer_stderr.timeout_id != 0L) {
/*
* Append a termination error message to whatever the
* printer process said, and pop it up.
*/
p = &printer_stderr;
space = PRINTER_BUF - p->count - 1;
if (p->count && *(p->buf + p->count - 1) != '\n') {
*(p->buf + p->count) = '\n';
p->count++;
space--;
}
(void) strncpy(p->buf + p->count, exitmsg, space);
p->count += strlen(exitmsg);
if (p->count >= PRINTER_BUF)
p->count = PRINTER_BUF - 1;
printer_dump(p, True, True);
} else {
popup_an_error(exitmsg);
}
printer_stop();
return;
}
/* Add it to the buffer, and add a NULL. */
p->count += nr;
p->buf[p->count] = '\0';
/*
* If there's no more room in the buffer, dump it now. Otherwise,
* give it a second to generate more output.
*/
if (p->count >= PRINTER_BUF - 1) {
printer_dump(p, is_err, False);
} else if (p->timeout_id == 0L) {
p->timeout_id = AddTimeOut(1000,
is_err? printer_etimeout: printer_otimeout);
}
}
/* The printer process has some output for us. */
static void
printer_output(void)
{
printer_data(&printer_stdout, False);
}
/* The printer process has some error output for us. */
static void
printer_error(void)
{
printer_data(&printer_stderr, True);
}
/* Timeout from printer output or error output. */
static void
printer_timeout(struct pr3o *p, Boolean is_err)
{
/* Forget the timeout ID. */
p->timeout_id = 0L;
/* Dump the output. */
printer_dump(p, is_err, False);
}
/* Timeout from printer output. */
static void
printer_otimeout(void)
{
printer_timeout(&printer_stdout, False);
}
/* Timeout from printer error output. */
static void
printer_etimeout(void)
{
printer_timeout(&printer_stderr, True);
}
/* Dump pending printer process output. */
static void
printer_dump(struct pr3o *p, Boolean is_err, Boolean is_dead)
{
if (p->count) {
/*
* Strip any trailing newline, and make sure the buffer is
* NULL terminated.
*/
if (p->buf[p->count - 1] == '\n')
p->buf[--(p->count)] = '\0';
else if (p->buf[p->count])
p->buf[p->count] = '\0';
/* Dump it and clear the buffer. */
#if defined(X3270_DISPLAY) /*[*/
popup_printer_output(is_err, is_dead? NULL: printer_stop,
"%s", p->buf);
#else /*][*/
action_output("%s", p->buf);
#endif
p->count = 0;
}
}
/* Close the printer session. */
void
printer_stop(void)
{
/* Remove inputs. */
if (printer_stdout.input_id) {
RemoveInput(printer_stdout.input_id);
printer_stdout.input_id = 0L;
}
if (printer_stderr.input_id) {
RemoveInput(printer_stderr.input_id);
printer_stderr.input_id = 0L;
}
/* Cancel timeouts. */
if (printer_stdout.timeout_id) {
RemoveTimeOut(printer_stdout.timeout_id);
printer_stdout.timeout_id = 0L;
}
if (printer_stderr.timeout_id) {
RemoveTimeOut(printer_stderr.timeout_id);
printer_stderr.timeout_id = 0L;
}
/* Clear buffers. */
printer_stdout.count = 0;
printer_stderr.count = 0;
/* Kill the process. */
#ifndef AMIGA
if (printer_pid != -1) {
(void) killpg(printer_pid, SIGTERM);
printer_pid = -1;
}
#endif
/* Tell everyone else. */
#ifndef AMIGA
st_changed(ST_PRINTER, False);
#endif
}
#if defined(X3270_DISPLAY) /*[*/
/* Callback for "OK" button on printer specific-LU popup */
static void
lu_callback(Widget w, XtPointer client_data, XtPointer call_data unused)
{
char *lu;
if (w) {
lu = XawDialogGetValueString((Widget)client_data);
if (lu == CN || *lu == '\0') {
popup_an_error("Must supply an LU");
return;
} else
XtPopdown(lu_shell);
} else
lu = (char *)client_data;
printer_start(lu);
}
#endif /*]*/
/* Host connect/disconnect/3270-mode event. */
static void
printer_host_connect(Boolean connected unused)
{
/*
* If we're no longer in 3270 mode, then we can no longer have a
* printer session. This may cause some fireworks if there is a
* print job pending when we do this, so some sort of awful timeout
* may be needed.
*/
if (!IN_3270)
printer_stop();
}
#if defined(X3270_DISPLAY) /*[*/
/* Pop up the LU dialog box. */
void
printer_lu_dialog(void)
{
if (lu_shell == NULL)
lu_shell = create_form_popup("printerLu",
lu_callback, (XtCallbackProc)NULL, FORM_NO_WHITE);
popup_popup(lu_shell, XtGrabExclusive);
}
#endif /*]*/
Boolean
printer_running(void)
{
return printer_pid != -1;
}
#endif /*]*/